Next.js - FQ

Next.js - FQ

How to use cssModules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# install next-css

yarn add @zeit/next-css

# use nextCss warpped the config
// next.config.js
const withLess = require('@zeit/next-less');
const withCSS = require('@zeit/next-css');
...
module.exports = withCSS(
withLess({
cssModules: true,
... // other config
})
);

# use css modules

import css from "../style.css";

const Component = props => {
return (
<div className={css.example}>
...
</div>
);
}

export default Component;

How to listen for routing changes?

The router of next provide some APIs that are used to listen for routing changes for us. For example: beforeHistoryChange, routeChangeComplete...

1
2
3
4
5
6
7
8
9
10
// _app.js

import Router from 'next/router';
...
// Listen the route path change
Router.events.on('routeChangeStart', (path) => {
console.log('route start change, the next route is:', path);
// do something what you want to do.
...
});

The solution of ant-design in the development environment style load is incomplete.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// next.config.js

const isDev = process.env.NODE_ENV !== 'production';

// fix antd bug in dev development
const devAntd = '@import "~antd/dist/antd.less";\n';
const stylesData = fs.readFileSync(
path.resolve(__dirname, './assets/_styles.less'),
'utf-8'
);
fs.writeFileSync(
path.resolve(__dirname, './assets/self-styles.less'),
isDev ? `${devAntd}${stylesData}` : stylesData,
'utf-8'
);

The solution of min-css-extract-plugin warning in the console

1
2
3
chunk commons [mini-css-extract-plugin]
Conflicting order between:
...

// next.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// define the webpack plugn
class FilterPlugin {
constructor(options) {
this.options = options;
}

apply(compiler) {
compiler.hooks.afterEmit.tap(
'FilterPlugin',
(compilation) => {
compilation.warnings = (compilation.warnings).filter(
warning => !this.options.filter.test(warning.message)
);
}
);
}
}

webpack: (config, {...args}) => {
config.plugins.push(
...[
// Instantiate the plugin and add it as a Webpack plugin
new FilterPlugin(
{ filter: /chunk styles \[mini-css-extract-plugin]\nConflicting order between:/ }
)
]
);
}

How to polyfill IE10/IE9 in this scaffold?

Add polyfills.js in your project.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// /core/polyfills.js
/* eslint no-extend-native: 0 */
// core-js comes with Next.js. So, you can import it like below
import includes from 'core-js/library/fn/string/virtual/includes';
import repeat from 'core-js/library/fn/string/virtual/repeat';
import assign from 'core-js/library/fn/object/assign';
import 'core-js/es6/map';
import 'core-js/es6/set';

// Add your polyfills
// This files runs at the very beginning (even before React and Next.js core)
console.log('Load your polyfills');

String.prototype.includes = includes;
String.prototype.repeat = repeat;
Object.assign = assign;

How to alias folder path?

1
2
3
4
5
// next.config.js

// config alias
config.resolve.alias['@containers'] =
path.resolve(__dirname, './src/containers');

Config the next.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// next.config.js
...
webpack: function (cfg) {
const originalEntry = cfg.entry
cfg.entry = async () => {
const entries = await originalEntry()

if (
entries['main.js'] &&
!entries['main.js'].includes('./core/polyfills.js')
) {
entries['main.js'].unshift('./core/polyfills.js')
}

return entries
}

return cfg
}
...

Downgrade your Next version to ‘7.0.2’

The ant-design style flash when page refresh!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// _app.js -> getInitialProps
/* 刷新页面 antd闪动 */
if (typeof window !== "undefined") {
window.onload = () => {
document.getElementById("flashStyle").remove();
};
}

// _app.js -> <Head></Head>
<style
id='flashStyle'
dangerouslySetInnerHTML={{
__html: `
*, *::before, *::after {
transition: none!important;
}
`
}}
/>

How to speed up packing in production?

1. tenser-webpack-plugin -> cache

1
2
3
4
5
6
new TerserPlugin({
cache: true, // add this line
terserOptions: {
...
}
}),

2. Add thread-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
config.module.rules.push({
test: /\.js$/,
include: [
path.resolve('src')
...
],
options: {
workerParallelJobs: 50,
// additional node.js arguments
workerNodeArgs: ['--max-old-space-size=1024'],
},
loader: 'thread-loader'
});

How to optimize bundle size?

Optimize moment local.

1
2
3
4
// next.config.js
const myWebpack = require('webpack');
...
new myWebpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn|en/),

Optimize antd icon dist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// next.config.js
...
config.resolve.alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, './assets/icons.js');
// /assets/icons.js

// 你自己手动引入的Icon,默认是outline
export {
default as LoginOutline
} from '@ant-design/icons/lib/outline/LoginOutline';
export {
default as LogoutOutline
} from '@ant-design/icons/lib/outline/LogoutOutline';
export {
default as UserOutline
} from '@ant-design/icons/lib/outline/UserOutline';
...
// 下面的 不是自己引入的,而是内置组件引入的,比如Input/Select/Datepicker等
export {
default as SearchOutline
} from '@ant-design/icons/lib/outline/SearchOutline';
export {
default as DownOutline
} from '@ant-design/icons/lib/outline/DownOutline';
export {
default as UpOutline
} from '@ant-design/icons/lib/outline/UpOutline';
export {
default as CalendarOutline
} from '@ant-design/icons/lib/outline/CalendarOutline';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
const fs = require("fs");
const withSass = require('@zeit/next-sass')
const withCss = require('@zeit/next-css');
const withBundleAnalyzer = require("@zeit/next-bundle-analyzer");
const webpack = require('webpack');
const path = require("path")

const PROD_FILE = "./config/prod.json";
const DEV_FILE = "./config/dev.json";
const LOCAL_FILE = "./config/local.json";

const readConfig = () => {
const prod = fs.existsSync(PROD_FILE);
if (prod) {
return fs.readFileSync(PROD_FILE)
} else {
if (process.env.NODE_ENV === 'production') {
return fs.readFileSync(DEV_FILE)
} else {
return fs.readFileSync(LOCAL_FILE)
}
}
// return prod ?
// fs.readFileSync(PROD_FILE) :
// !fs.existsSync(LOCAL_FILE) ?
// fs.readFileSync(DEV_FILE) :
// fs.readFileSync(LOCAL_FILE)
}


// fix: prevents error when .css files are required by node
if (typeof require !== 'undefined') {
require.extensions['.css'] = file => {}
require.extensions['.scss'] = file => {}
}

const config = JSON.parse(readConfig().toString());
// console.log("config is :", config);

const webpackConfig = (config, {}) => {
const originalEntry = config.entry;
config.entry = async () => {
const entries = await originalEntry();
if (entries['main.js']) {
entries['main.js'].unshift('./polyfills.js');
}
return entries;
};

config.module.rules.push({
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
}]
}),
config.plugins.push(
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn|en/),
);
// comstom antd icon
config.resolve.alias["@ant-design/icons/lib/dist$"] = path.resolve(__dirname, './common/icon.ts');

return config;
};

module.exports = withSass(withCss(withBundleAnalyzer({
analyzeServer: ["server", "both"].includes(
process.env.BUNDLE_ANALYZE
),
analyzeBrowser: ["browser", "both"].includes(
process.env.BUNDLE_ANALYZE
),
bundleAnalyzerConfig: {
server: {
analyzerMode: "static",
reportFilename: "../bundles/server.html"
},
browser: {
analyzerMode: "static",
reportFilename: "../bundles/client.html"
}
},
serverRuntimeConfig: config.server,
publicRuntimeConfig: config.client,
distDir: "_next",
webpack: webpackConfig,
assetPrefix: process.env.NODE_CDN == "true" && config ?
config.deploy.host + config.deploy.version : ""
})));

Thanks: luffyZh update FAQ

感谢你的打赏哦!